package cc.fine.svc.security.filter;

import cc.fine.svc.config.redis.utils.RedisCache;
import cc.fine.svc.security.utils.IPUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
@Slf4j
public class IpFilter extends OncePerRequestFilter {

    @Autowired
    private RedisCache redisCache;

    // 白名单每秒访问阈值(同一个IP/次)
    private static final Integer WRITE_TIMES = 40;

    // 黑名单持续时间(s)
    private static final Integer BLACK_TIME = 300;

    public boolean handler(HttpServletRequest request) {
        // 直接放行 对swagger的访问
        String servletPath = request.getServletPath();
        if (servletPath.contains("swagger") || servletPath.contains("/v2/api-docs")) {
            return true;
        }

        String realIP = IPUtils.getRealIP(request);

        log.info("真实ip: {}", realIP);

        String blackKey = "limit:black:ip:" + realIP;
        String writeKey = "limit:write:ip:" + realIP;

        // 黑名单中是否有该ip，如果有，不放行，没有继续
        Object blackValue = redisCache.getCacheObject(blackKey);
        if (blackValue != null) {
            log.info("ip {} 黑名单禁止访问", realIP);
            return false;
        }

        // 白名单中是否存在，如果存在，值+1， 如果不存在，创建并设置过期时间
        Object writeValue = redisCache.getCacheObject(writeKey);
        if (writeValue != null) {
            redisCache.increment(writeKey);
        } else {
            redisCache.setCacheObject(writeKey, 1);
            redisCache.expire(writeKey, 1);
            writeValue = 1;
        }

        log.info("白名单中访问次数 {}", writeValue);

        // 如果值>15，加入黑名单，不放行
        if ((Integer) writeValue > WRITE_TIMES) {
            redisCache.setCacheObject(blackKey, true);
            redisCache.expire(blackKey, BLACK_TIME);
            log.info("ip {} 加入黑名单", realIP);
            return false;
        }


        return true;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//        boolean flag = handler(request);
//        if (flag) {
//            filterChain.doFilter(request, response);
//        }
        filterChain.doFilter(request, response);
    }
}
